import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState, AppThunk } from '../../app/store';
import { fetchOrder } from './indexApi';
// import type { ChannelProps } from './components/Channel/index';
// import { ListItemProps, TrainQuery } from './types';
import type { OrderQuery, PassengerUpdateProps, PassengerProps } from './types';

const getSpeedId = (): (() => number) => {
  let passengerIdSeed = 0;
  return (): number => {
    return passengerIdSeed++;
  };
};

export interface OrderState {
  orderDetail: {
    data: {
      departTimeStr: string;
      arriveTimeStr: string;
      arriveDate: number | null;
      durationStr: string | null;
    };
    // trainType: string;
    // depStation: string;
    // arrStation: string;
    status: 'idle' | 'loading' | 'failed' | 'success';
  };
  passengers: PassengerProps[];
}

const initialState: OrderState = {
  orderDetail: {
    data: {
      departTimeStr: '',
      arriveTimeStr: '',
      arriveDate: null,
      durationStr: null,
    },
    status: 'idle',
  },
  passengers: [],
};

// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
export const getOrderAsync = createAsyncThunk(
  'order/fetchTicketList',
  async (queryParams: OrderQuery) => {
    const response: any = await fetchOrder(queryParams);
    // The value we return becomes the `fulfilled` action payload
    return response.data;
  }
);

const getId = getSpeedId();
export const orderSlice = createSlice({
  name: 'order',
  initialState,
  // The `reducers` field lets us define reducers and generate associated actions
  reducers: {
    createAdult: (state, value: any) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      // state.value += 1;
      if (value.payload.length != 0) {
        state.passengers.push(...value.payload);
      } else {
        state.passengers.push({
          id: getId(),
          name: '',
          ticketType: 'adult',
          licenceNo: '',
          seat: 'Z',
        });
      }
    },
    createChild: (state) => {
      let adultFound = null;
      const passengers = state.passengers;

      for (const passenger of passengers) {
        if (passenger.ticketType === 'adult') {
          adultFound = passenger.id;
        }
      }

      if (!adultFound) {
        alert('请至少正确添加一个同行成人');
        return;
      }
      state.passengers.push({
        id: getId(),
        name: '',
        gender: 'none',
        birthday: '',
        followAdult: adultFound,
        ticketType: 'child',
        seat: 'Z',
      });
      // state.value -= 1;
    },
    removePassenger: (state, action: PayloadAction<number>) => {
      const passengers = state.passengers;
      const newPassengers = passengers.filter((passenger) => {
        return (
          passenger.id !== action.payload &&
          passenger.followAdult !== action.payload
        );
      });
      state.passengers = newPassengers;
    },
    updatePassenger: (
      state,
      action: PayloadAction<{
        id: number;
        data: PassengerUpdateProps;
      }>
    ) => {
      const passengers = state.passengers;
      for (let i = 0; i < passengers.length; ++i) {
        if (passengers[i].id === action.payload.id) {
          // const newPassengers = [...passengers];
          passengers[i] = {
            ...passengers[i],
            ...action.payload.data,
          };

          // for (const key of keysToBeRemoved) {
          //   delete newPassengers[i][key];
          // }
        }
      }
      state.passengers = passengers;
    },
    // Use the PayloadAction type to declare the contents of `action.payload`
  },
  // The `extraReducers` field lets the slice handle actions defined elsewhere,
  // including actions generated by createAsyncThunk or in other slices.
  extraReducers: (builder) => {
    builder
      .addCase(getOrderAsync.pending, (state) => {
        state.orderDetail.status = 'loading';
      })
      .addCase(getOrderAsync.fulfilled, (state, action) => {
        state.orderDetail.status = 'success';
        state.orderDetail.data = action.payload;
      })
      .addCase(getOrderAsync.rejected, (state) => {
        state.orderDetail.status = 'failed';
      });
  },
});

// export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
export const selectOrder = (state: RootState) => state.order.orderDetail.data;
export const selectPassengers = (state: RootState) => state.order.passengers;
// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
// export const incrementIfOdd =
//   (amount: number): AppThunk =>
//   (dispatch, getState) => {
//     const currentValue = selectCount(getState());
//     if (currentValue % 2 === 1) {
//       dispatch(incrementByAmount(amount));
//     }
//   };
export const { createAdult, createChild, removePassenger, updatePassenger } =
  orderSlice.actions;
export default orderSlice.reducer;
